#include <algorithm>

#include "GWindow.h"
#include "GMessageManager.h"
#include "GMessageHandler.h"
#include "GError.h"


namespace GEngine
{
	GMessageManager::GMessageManager()
	{
		EnableDelay = true;
	}

	GMessageManager::~GMessageManager()
	{
	}

	GSize GMessageManager::GetHandlerCount() const
	{
		return Handlers.size();
	}

	void GMessageManager::SetEnableDelay(bool Value)
	{
		EnableDelay = Value;	
	}

	bool GMessageManager::GetEnableDelay() const
	{
		return EnableDelay;
	}

	void GMessageManager::DispatchMessages()
	{
		MessageArray MessagesCopy(Messages);
		Messages.clear();

		// Send delayed messages
		GSSize Result = 0;
		MessageArray::iterator Current = MessagesCopy.begin();

		GUInt32 Count = 0;
		while (Current != MessagesCopy.end())
		{
			InstantMessage(Current->first, Current->second);
			Current++;

			Count++;
		}

		MessagesCopy.clear();
	}

	void GMessageManager::AppendHandler(GMessageHandler* Handler)
	{
		GWindow* Target = Handler->GetTargetWindow();
		Handlers.insert(HandlerMap::value_type(Target, Handler));
	}

	void GMessageManager::RemoveHandler(GMessageHandler* Handler)
	{
		GWindow* Target = Handler->GetTargetWindow();
		Handlers.erase(Target);
	}

	// Synchronous message sending
	// NULL target means only global handlers will recieve it
	bool GMessageManager::InstantMessage(GWindow* Target, const GSystemMessage& Message)
	{
		GSSize Handled = 0;
		HandlerMap::local_iterator Iter;

		// Send message to all handlers of the target window
		auto Range = Handlers.equal_range(Target);
		for (auto Iter = Range.first; Iter != Range.second; ++Iter) 
		{
			Handled |= Iter->second->HandleMessage(&Message);
		}

		// Also send the message to global handlers
		if (Target != NULL)
		{
			auto Range = Handlers.equal_range(NULL);
			for (auto Iter = Range.first; Iter != Range.second; ++Iter) 
			{
				Handled |= Iter->second->HandleMessage(&Message);
			}
		}

		// Return true if all handers processed their messages sucessfully
		return Handled == 0;
	}

	// Asynchronous message sending
	// Messages are dispatched then the message manager's Update method is called.
	void GMessageManager::DelayedMessage(GWindow* Target, const GSystemMessage& Message)
	{
		GUtil::GError::DebugCheck(Messages.size() == G_MAX_BUFFERED_MSG_COUNT, "Message queue is full.");

		if (EnableDelay)
		{
			// Queue
			Messages.emplace_back(Target, Message);
		}
		else
		{
			// Process
			InstantMessage(Target, Message);
		}
	}

	bool GMessageManager::Initialize() OVERRIDE
	{
		if (!GInitializable::Initialize())
		{
			return false;
		}

		const GSize BucketCount = 16;

		// Pre allocate pool
		Messages.reserve(G_MAX_BUFFERED_MSG_COUNT);
		Handlers.rehash(BucketCount);

		return true;
	}

	void GMessageManager::Uninitialize() OVERRIDE
	{
		// clear all
		Messages.clear();
		Handlers.clear();

		GInitializable::Uninitialize();
	}
	
}
